package gns

import (
	"fmt"
	"io"
	"net"
	"strconv"
	"time"

	"gitee.com/liumou_site/logger"
)

// 需要用到 buildDNSQuery
//go:linkname buildDNSQuery gns.buildDNSQuery

// PortTcpStatus 检查指定IP和端口是否可以成功建立TCP连接。
func PortTcpStatus(ip, port string, out time.Duration) bool {
	conn, err := net.DialTimeout("tcp", net.JoinHostPort(ip, port), time.Second*out)
	if err != nil {
		logger.Error("连接错误: %s", err)
		return false
	}
	defer func(conn net.Conn) {
		err := conn.Close()
		if err != nil {
			logger.Error("关闭连接错误: %s", err)
		}
	}(conn)
	logger.Info("连接成功: [ %s:%s ]", ip, port)
	return true
}

// ConnError 表示在连接操作过程中发生的错误
// 该结构体用于封装连接相关的错误信息，通常用于网络操作或服务连接场景
type ConnError struct {
	Message string
}

func (e *ConnError) Error() string {
	return e.Message
}

// PortUdpStatus 检查指定IP和端口的UDP连接状态。
func PortUdpStatus(ip string, port int, timeout time.Duration) error {
	var errInfo error
	addr := net.JoinHostPort(ip, strconv.Itoa(port))
	conn, err := net.DialTimeout("udp", addr, timeout)
	if err != nil {
		errInfo = fmt.Errorf("连接错误: %v - 地址: %s\n", err, addr)
		logger.Error(errInfo)
		return &ConnError{Message: errInfo.Error()}
	}
	defer func(conn net.Conn) {
		err = conn.Close()
		if err != nil {
			logger.Error(fmt.Errorf("关闭连接错误: %v - 地址: %s", err, addr))
		}
	}(conn)
	query := buildDNSQuery("example.com")
	logger.Info(fmt.Sprintf("发送数据包: %x - 地址: %s", query, addr))
	_, err = conn.Write(query)
	if err != nil {
		errInfo = fmt.Errorf("发送数据包错误: %v - 地址: %s", err, addr)
		logger.Error(errInfo)
		return &ConnError{Message: errInfo.Error()}
	}
	err = conn.SetReadDeadline(time.Now().Add(timeout))
	if err != nil {
		errInfo = fmt.Errorf("设置读取超时错误: %v - 地址: %s", err, addr)
		logger.Error(errInfo)
		return &ConnError{Message: errInfo.Error()}
	}
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil {
		if err == io.EOF {
			logger.Error(fmt.Sprintf("读取数据包错误: EOF - 地址: %s", addr))
			return &ConnError{Message: fmt.Sprintf("读取数据包错误: EOF - 地址: %s", addr)}
		}
		errInfo = fmt.Errorf("读取数据包错误: %v - 地址: %s", err, addr)
		logger.Error(errInfo)
		return &ConnError{Message: errInfo.Error()}
	}
	logger.Debug(fmt.Sprintf("接收到的数据包: %x - 地址: %s", buf[:n], addr))
	logger.Info("连接成功: ", addr)
	return nil
}
